import os
import re
import subprocess
import platform
import traceback
from .utils import get_startupinfo

class VideoOperations:
    def __init__(self):
        pass
        
    def merge_videos(self):
        """合并左右眼视频"""
        try:
            self.log_message.emit(f"===== 开始合并左右眼视频 =====")
            self.log_message.emit(f"左眼视频: {self.left_eye_video}")
            self.log_message.emit(f"右眼视频: {self.right_eye_video}")
            self.log_message.emit(f"输出视频: {self.output_video}")
            
            # 首先获取视频的高度 - 改进视频尺寸获取方法
            video_height = None
            video_width = None
            
            # 使用ffprobe直接获取视频信息，更可靠
            try:
                ffprobe_path = os.path.join(os.path.dirname(self.ffmpeg_path), "ffprobe.exe")
                if os.path.exists(ffprobe_path):
                    command = [
                        ffprobe_path,
                        "-v", "error",
                        "-select_streams", "v:0",
                        "-show_entries", "stream=width,height",
                        "-of", "json",
                        self.left_eye_video
                    ]
                    
                    startupinfo = get_startupinfo()
                    
                    result = subprocess.run(
                        command,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        text=True,
                        startupinfo=startupinfo
                    )
                    
                    # 尝试解析JSON输出
                    import json
                    try:
                        video_info = json.loads(result.stdout)
                        if 'streams' in video_info and len(video_info['streams']) > 0:
                            stream = video_info['streams'][0]
                            if 'width' in stream and 'height' in stream:
                                video_width = int(stream['width'])
                                video_height = int(stream['height'])
                                self.log_message.emit(f"使用ffprobe获取视频尺寸: {video_width}x{video_height}")
                    except json.JSONDecodeError:
                        self.log_message.emit("无法解析ffprobe的JSON输出")
            except Exception as e:
                self.log_message.emit(f"使用ffprobe获取视频尺寸出错: {str(e)}")
            
            # 如果上面的方法失败，尝试使用正则表达式从ffprobe输出中提取
            if video_height is None or video_height <= 0:
                try:
                    command = [
                        ffprobe_path,
                        "-v", "error",
                        "-select_streams", "v:0",
                        "-show_entries", "stream=width,height",
                        "-of", "default=noprint_wrappers=1",
                        self.left_eye_video
                    ]
                    
                    result = subprocess.run(
                        command,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                        text=True,
                        startupinfo=startupinfo
                    )
                    
                    # 使用正则表达式提取宽度和高度
                    width_match = re.search(r"width=(\d+)", result.stdout)
                    height_match = re.search(r"height=(\d+)", result.stdout)
                    
                    if width_match and height_match:
                        video_width = int(width_match.group(1))
                        video_height = int(height_match.group(1))
                        self.log_message.emit(f"使用ffprobe正则提取视频尺寸: {video_width}x{video_height}")
                except Exception as e:
                    self.log_message.emit(f"使用正则提取视频尺寸出错: {str(e)}")
            
            # 如果仍然无法获取，使用默认值
            if video_height is None or video_height <= 0:
                video_height = 1080  # 默认高度
                video_width = 1920   # 默认宽度
                self.log_message.emit(f"无法获取视频尺寸，使用默认值: {video_width}x{video_height}")
            
            # 获取视频时长，用于计算进度
            duration = self.get_video_duration(self.left_eye_video)
            if duration:
                self.log_message.emit(f"视频时长: {duration:.2f}秒")
            
            # 构建FFmpeg命令
            command = [self.ffmpeg_path]
            
            # 修复硬件加速选项
            hw_accel_used = False
            self.log_message.emit(f"硬件加速类型：{self.hardware_accel}")
            if hasattr(self, 'hardware_accel') and self.hardware_accel and self.hardware_accel.lower() != "cpu":
                # 提取实际的硬件加速类型（去除描述文本）
                actual_accel = self.hardware_accel.lower().split()[0] if " " in self.hardware_accel else self.hardware_accel.lower()
                
                # 确保CUDA被正确识别
                if "cuda" in actual_accel:
                    command.extend(["-hwaccel", "cuda"])
                    self.log_message.emit(f"使用CUDA硬件加速")
                else:
                    command.extend(["-hwaccel", actual_accel])
                    self.log_message.emit(f"使用硬件加速: {actual_accel}")
                hw_accel_used = True
            else:
                self.log_message.emit("使用CPU处理")
            
            # 添加输入视频
            command.extend(["-i", self.left_eye_video, "-i", self.right_eye_video])
            
            # 构建滤镜复杂命令 - 修复分割线问题
            filter_complex = ""
            if hasattr(self, 'black_line') and self.black_line and hasattr(self, 'black_line_width') and self.black_line_width > 0:
                # 使用pad滤镜添加黑色边框，然后使用hstack合并
                # 为左侧视频添加右侧黑色边框
                filter_complex = f"[0:v]pad=iw+{self.black_line_width}:ih:iw:0:black[left_padded];"
                # 合并左侧带边框的视频和右侧视频
                filter_complex += "[left_padded][1:v]hstack=inputs=2"
                self.log_message.emit(f"添加黑色分隔线，宽度: {self.black_line_width}像素")
            else:
                filter_complex = "[0:v][1:v]hstack=inputs=2"
                self.log_message.emit("不添加分隔线")
            
            command.extend(["-filter_complex", filter_complex])
            
            # 添加输出选项
            command.extend([
                "-c:v", "libx264",
                "-preset", "medium",
                "-crf", "23",
                "-y",  # 覆盖已存在的文件
                self.output_video
            ])
            
            # 打印命令
            command_str = " ".join(command)
            self.log_message.emit(f"FFmpeg命令: {command_str}")
            
            # 创建无窗口进程
            startupinfo = get_startupinfo()
            
            # 执行命令
            process = subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                universal_newlines=True,
                startupinfo=startupinfo
            )
            
            # 读取输出并更新进度
            total_frames = 0
            if duration:
                # 估算总帧数 (假设30fps)
                fps = 30
                total_frames = int(duration * fps)
            
            # 初始化进度为0
            self.progress_updated.emit(0)
            
            # 添加超时机制，防止进程卡住
            import threading
            process_finished = False
            
            def check_timeout():
                # 如果5分钟后进程仍未结束，强制终止
                if not process_finished:
                    try:
                        process.terminate()
                        self.log_message.emit("处理超时，已强制终止")
                        self.process_completed.emit(False, "处理超时")
                    except:
                        pass
            
            # 设置5分钟超时
            timeout_timer = threading.Timer(300, check_timeout)
            timeout_timer.daemon = True
            timeout_timer.start()
            
            try:
                # 读取输出
                for line in process.stdout:
                    if self.should_stop:
                        process.terminate()
                        self.log_message.emit("用户取消了视频合并")
                        self.process_completed.emit(False, "用户取消")
                        return
                    
                    # 输出日志
                    self.log_message.emit(line.strip())
                    
                    # 尝试从输出中提取当前帧和时间
                    frame_match = re.search(r"frame=\s*(\d+)", line)
                    time_match = re.search(r"time=(\d+):(\d+):(\d+)\.(\d+)", line)
                    
                    if frame_match and total_frames > 0:
                        current_frame = int(frame_match.group(1))
                        progress = min(int(current_frame / total_frames * 100), 99)  # 最大99%，留1%给最后处理
                        self.progress_updated.emit(progress)
                        
                        # 每处理100帧输出一次进度
                        if current_frame % 100 == 0:
                            self.log_message.emit(f"合并进度: {progress}%")
                    
                    elif time_match and duration:
                        # 如果有时间信息，也可以用来计算进度
                        h, m, s, ms = map(int, time_match.groups())
                        current_time = h * 3600 + m * 60 + s + ms / 100
                        progress = min(int(current_time / duration * 100), 99)
                        self.progress_updated.emit(progress)
                        
                        # 每10%输出一次进度
                        if progress % 10 == 0:
                            self.log_message.emit(f"合并进度: {progress}%")
                
                # 等待进程完成，但设置超时
                try:
                    return_code = process.wait(timeout=300)  # 5分钟超时
                    process_finished = True
                    timeout_timer.cancel()  # 取消超时计时器
                    
                    # 检查返回码
                    if return_code == 0:
                        self.progress_updated.emit(100)  # 设置为100%完成
                        self.log_message.emit(f"视频合并成功: {self.output_video}")
                        self.process_completed.emit(True, "视频合并成功")
                    else:
                        self.log_message.emit(f"视频合并失败，返回码: {return_code}")
                        
                        # 如果使用硬件加速失败，尝试使用CPU
                        if hw_accel_used:
                            self.log_message.emit("硬件加速可能失败，尝试使用CPU重试...")
                            self.hardware_accel = "cpu"
                            self.merge_videos()  # 递归调用，使用CPU重试
                        else:
                            self.process_completed.emit(False, f"视频合并失败，返回码: {return_code}")
                except subprocess.TimeoutExpired:
                    process.terminate()
                    self.log_message.emit("处理超时，已终止")
                    self.process_completed.emit(False, "处理超时")
            finally:
                # 确保超时计时器被取消
                timeout_timer.cancel()
        
        except Exception as e:
            self.log_message.emit(f"合并视频时出错: {str(e)}")
            self.log_message.emit(traceback.format_exc())
            self.process_completed.emit(False, f"合并视频时出错: {str(e)}")

    def get_video_height(self, video_path):
        """获取视频高度"""
        try:
            # 使用更通用的方式获取视频信息
            command = [
                self.ffmpeg_path,
                "-i", video_path,
                "-v", "error"
            ]
            
            # 创建无窗口进程
            startupinfo = get_startupinfo()
            
            # 执行命令
            result = subprocess.run(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                startupinfo=startupinfo
            )
            
            # 从输出中解析视频高度
            output = result.stderr  # FFmpeg将信息输出到stderr
            height_match = re.search(r"(\d+)x(\d+)", output)
            if height_match:
                width, height = map(int, height_match.groups())
                self.log_message.emit(f"视频尺寸: {width}x{height}")
                return height
            else:
                self.log_message.emit(f"无法从输出中解析视频高度")
                return None
        except Exception as e:
            self.log_message.emit(f"获取视频高度出错: {str(e)}")
            return None

    def get_video_duration(self, video_path):
        """获取视频时长（秒）"""
        try:
            # 使用ffprobe获取视频时长
            ffprobe_path = os.path.join(os.path.dirname(self.ffmpeg_path), "ffprobe.exe")
            if not os.path.exists(ffprobe_path):
                self.log_message.emit("找不到ffprobe，无法获取视频时长")
                return None
            
            command = [
                ffprobe_path,
                "-v", "error",
                "-show_entries", "format=duration",
                "-of", "csv=p=0",
                video_path
            ]
            
            startupinfo = get_startupinfo()
            
            result = subprocess.run(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                startupinfo=startupinfo
            )
            
            if result.stdout.strip():
                try:
                    duration = float(result.stdout.strip())
                    return duration
                except ValueError:
                    self.log_message.emit(f"无法解析视频时长: {result.stdout.strip()}")
            
            # 如果上面的方法失败，尝试使用FFmpeg获取
            command = [
                self.ffmpeg_path,
                "-i", video_path,
                "-hide_banner"
            ]
            
            process = subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                universal_newlines=True,
                startupinfo=startupinfo
            )
            
            stdout, stderr = process.communicate()
            
            # 从输出中解析时长
            duration_match = re.search(r"Duration: (\d+):(\d+):(\d+)\.(\d+)", stderr)
            
            if duration_match:
                hours = int(duration_match.group(1))
                minutes = int(duration_match.group(2))
                seconds = int(duration_match.group(3))
                milliseconds = int(duration_match.group(4))
                
                total_seconds = hours * 3600 + minutes * 60 + seconds + milliseconds / 100
                return total_seconds
            
            return 0
        
        except Exception as e:
            self.log_message.emit(f"获取视频时长出错: {str(e)}")
            return 0